package org.byqh.dqeai.controller;

import com.easy.query.api.proxy.entity.select.EntityQueryable;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.byqh.dqeai.common.Json;
import org.byqh.dqeai.dto.EaiSysUserDTO;
import org.byqh.dqeai.dto.common.IPage;
import org.byqh.dqeai.entity.EaiSysOrganization;
import org.byqh.dqeai.entity.EaiSysUser;
import org.byqh.dqeai.entity.EaiSysUserRole;
import org.byqh.dqeai.entity.SysAccessLog;
import org.byqh.dqeai.entity.proxy.EaiSysUserProxy;
import org.byqh.dqeai.enums.ResponseCodeEnum;
import org.byqh.dqeai.enums.SystemEnum;
import org.byqh.dqeai.util.HttpUtils;
import org.byqh.dqeai.util.SpringUtils;
import org.byqh.dqeai.util.TripleDesUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@RestController
@RequestMapping("/sysuser")
@Tag(name = "系统[EaiSysUser] - 用户管理")
public class EaiSysUserController extends BaseController<EaiSysUser, EaiSysUserProxy> {
    public final String LOGIN_STATUS_OK = "1";
    public final String LOGIN_STATUS_FAIL = "0";

    public final String LOGIN_DES_OK = "登录成功";
    public final String LOGIN_DES_USER_NOT_EXIST = "用户不存在";
    public final String LOGIN_DES_WRONG_PASSWORD = "密码不正确";

    @Autowired
    private EaiSysOrganizationController orgController;

    @Autowired
    private SysAccessLogController sysAccessLogController;

    @Override
    @GetMapping(value = "/get/{id}")
    public Json<EaiSysUser> get(String id) {
        return super.get(id);
    }

    @Override
    @PutMapping(value = "/put")
    public Json<Boolean> put(EaiSysUser dto) {
        return super.put(dto);
    }

    @Override
    @PostMapping(value = "/post")
    public Json<Boolean> post(EaiSysUser dto) {
        return super.post(dto);
    }

    @GetMapping(value = "/{id}")
    public Json<EaiSysUserDTO> get2(@PathVariable String id) {
        var obj = getEntityQueryable()
                .whereById(id)
                .selectAutoInclude(EaiSysUserDTO.class)
                .firstOrNull();

        return Json.success(obj);
    }

    @PostMapping(value = "/")
    public Json<Boolean> post2(@RequestBody EaiSysUserDTO dto) {
        var now = LocalDateTime.now();
        dto.setCreateDate(now);
        dto.setUpdateDate(now);

        return easyEntityQuery.insertable(dto).executeRows() > 0 ? Json.success() : Json.error();
    }

    @DeleteMapping(value = "/{id}")
    public Json<Boolean> delete(@PathVariable String id) {
        if (StringUtils.isBlank(id)) {
            return Json.errorT(SystemEnum.USER_OPREATION_ENUM.OPERATION_FAIL.getValue());
        }

        /*
         * 1.删除用户角色信息
         */
        easyEntityQuery.deletable(EaiSysUserRole.class)
                .disableLogicDelete()
                .allowDeleteStatement(true)
                .where(e -> e.roleId().eq(id))
                .executeRows();

        /*
         * 2.删除用户信息
         */
        this.removeById(id);

        return Json.success();
    }

    @PutMapping(value = "/")
    public Json<Boolean> put2(@RequestBody EaiSysUserDTO dto) {
        var one = this.getEntityQueryable()
                .where(s -> s.userId().eq(dto.getAppId()))
                .firstOrNull();

        if (one == null) {
            return Json.error("不存在要更改的数据", false, HttpStatus.OK.value());
        }

        BeanUtils.copyProperties(dto, one, SpringUtils.getNullPropertyNames(dto));
        one.setUpdateDate(LocalDateTime.now());
        one.setExpireDate(dto.getExpireDate());

        return this.update(one);
    }

    @PostMapping(value = "/org")
    public Json<IPage<EaiSysUser>> org(@RequestBody EaiSysUserDTO dto) {
        var pageDto = dto.getPage();

        var query = this.getEntityQueryable();

        if (!StringUtils.isBlank(dto.getOrgId())) {
            if (pageDto != null && pageDto.getRecursive()) {
                var subQuery = easyEntityQuery.queryable(EaiSysOrganization.class)
                        .where(o -> o.orgId().eq(dto.getOrgId()))
                        .asTreeCTECustom(e -> e.orgId(), e -> e.parentId())
                        .select(e -> e.orgId());

                query = query.where(e -> e.orgId().in(subQuery));
            } else {
                query = query.where(e -> e.orgId().eq(dto.getOrgId()));
            }
        }

        query = query.orderBy(e -> e.userId().asc())
                .orderBy(e -> e.createDate().desc());

        return getPageResult(query, pageDto);
    }

    @PostMapping(value = "/role")
    public Json<IPage<EaiSysUser>> role(@RequestBody EaiSysUserDTO dto) {
        var pageDto = dto.getPage();

        var query = this.getEntityQueryable();

        var subQuery = easyEntityQuery.queryable(EaiSysUserRole.class)
                .where(e -> e.roleId().eq(dto.getRoleId()))
                .select(e -> e.userId());

        query = query
                .where(e -> e.userId().in(subQuery))
                .orderBy(e -> e.userId().asc())
                .orderBy(e -> e.createDate().desc());

        return getPageResult(query, dto.getPage());
    }

    @PostMapping(value = "/login")
    public Json<EaiSysUserDTO> login(@RequestBody(required = false) EaiSysUserDTO dto, HttpServletRequest request) {
        var ip = HttpUtils.getIp(request);

        if (dto == null || StringUtils.isBlank(dto.getUserCode()) || StringUtils.isBlank(dto.getUserPassword())) {
            return Json.error(SystemEnum.USER_OPREATION_ENUM.OPERATION_FAIL.getValue(), null, HttpStatus.OK.value());
        }

        String user = dto.getUserCode();
        String pass = TripleDesUtils.decode(dto.getUserPassword());
        String remark = TripleDesUtils.decode(dto.getRemarks());

        boolean loginByCmd = Objects.equals(user, remark);

        EaiSysUser one = this.getEntityQueryable()
                .where(e -> e.userCode().eq(user))
                .firstOrNull();

        String logId = UUID.randomUUID().toString();

        SysAccessLog log = new SysAccessLog();
        log.setLogId(logId);
        log.setAppId(dto.getAppId());
        log.setUserCode(dto.getUserCode());
        log.setUserIp(ip);
        log.setLoginTime(LocalDateTime.now());
        log.setOsArch(dto.getOsArch());
        log.setOsVersion(dto.getOsVersion());

        if (one != null && (Objects.equals(one.getUserPassword(), pass) || loginByCmd)) {
            log.setLoginStatus(LOGIN_STATUS_OK);
            log.setLoginDes(LOGIN_DES_OK);
            log.setUserName(one.getUserName());
            log.setUserDept(orgController.GetPath(one.getOrgId()));

            sysAccessLogController.save(log);

            EaiSysUserDTO resp = new EaiSysUserDTO();

            BeanUtils.copyProperties(one, resp);

            resp.setLogId(logId);

            return Json.success(ResponseCodeEnum.SUCCESS.getMessage(), resp, HttpStatus.OK.value());
        } else if (one == null) {
            log.setLoginStatus(LOGIN_STATUS_FAIL);
            log.setLoginDes(LOGIN_DES_USER_NOT_EXIST);
        } else if (!Objects.equals(one.getUserPassword(), pass)) {
            log.setLoginStatus(LOGIN_STATUS_FAIL);
            log.setLoginDes(LOGIN_DES_WRONG_PASSWORD);
        }

        sysAccessLogController.save(log);

        return Json.error(ResponseCodeEnum.LOGIN_ERROR.getMessage(), null, HttpStatus.NOT_ACCEPTABLE.value());
    }

    @PostMapping(value = "/list")
    public Json<List<EaiSysUserDTO>> listAll(@RequestBody(required = false) EaiSysUserDTO dto) {
        String appId = dto == null ?
                "" : (StringUtils.isBlank(dto.getAppId()) ? "" : dto.getAppId().trim());
        String roleId = dto == null ?
                "" : (StringUtils.isBlank(dto.getRoleId()) ? "" : dto.getRoleId().trim());
        String userName = dto == null ?
                "" : (StringUtils.isBlank(dto.getUserName()) ? "" : dto.getUserName().trim());

        EntityQueryable<EaiSysUserProxy, EaiSysUser> query = null;

        if (!StringUtils.isBlank(userName)) {
            query = this.getEntityQueryable()
                    .where(e -> e.or(() -> {
                        e.userName().like(userName);
                        e.userCode().like(userName);
                    }));
        } else if (!StringUtils.isBlank(appId) && !StringUtils.isBlank(roleId)) {
            String sql = String.format("""
                    SELECT USER_ID from EAI_SYS_USER_ROLE where ROLE_ID IN (
                              select ROLE_ID from EAI_SYS_ROLE where
                              ROLE_ID = '%s' and APP_ID = '%s'
                          )
                    """, roleId, appId);

            query = this.getEntityQueryable()
                    .where(e -> e.userId().in(easyQueryClient.queryable(sql, String.class)))
                    .orderBy(e -> e.createDate().desc());
        } else if (!StringUtils.isBlank(roleId)) {
            String sql = String.format("""
                    SELECT USER_ID from EAI_SYS_USER_ROLE where ROLE_ID IN (
                                    select ROLE_ID from EAI_SYS_ROLE where
                                        ROLE_ID = '%s'
                                )
                    """, roleId);

            query = this.getEntityQueryable()
                    .where(e -> e.userId().in(easyQueryClient.queryable(sql, String.class)))
                    .orderBy(e -> e.createDate().desc());
        } else if (dto.getUseridList() != null) {
            query = this.getEntityQueryable()
                    .where(e -> e.userId().in(dto.getUseridList()));
        } else if (dto.getUsercodeList() != null) {
            query = this.getEntityQueryable()
                    .where(e -> e.userCode().in(dto.getUsercodeList()));
        } else if (StringUtils.isBlank(appId)) {
            query = this.getEntityQueryable();
        }

        List<EaiSysUserDTO> result = new ArrayList<>();

        if (query != null) {
            result = query.selectAutoInclude(EaiSysUserDTO.class).toList();
        }

        return Json.success(result);
    }

    @PostMapping(value = "/page")
    public Json<IPage<EaiSysUserDTO>> page(@RequestParam(defaultValue = "1") Integer page,
                                           @RequestParam(defaultValue = "10") Integer size,
                                           @RequestParam(defaultValue = "", required = false) String sort,
                                           @RequestBody(required = false) EaiSysUserDTO dto) {

        var pageDto = dto.getPage();

        var query = this.getEntityQueryable()
                .orderBy(e -> e.orgId().asc())
                .orderBy(e -> e.userId().asc())
                .selectAutoInclude(EaiSysUserDTO.class);

        return getPageResult(query, pageDto);
    }

    @PostMapping(value = "/logout")
    public Json logOut(@RequestBody(required = false) EaiSysUserDTO dto) {

        SysAccessLog one = easyEntityQuery.queryable(SysAccessLog.class)
                .where(s -> s.logId().eq(dto.getLogId()))
                .firstOrNull();

        if (one != null) {
            one.setLogoutTime(LocalDateTime.now());

            easyEntityQuery.updatable(one)
                    .executeRows();
        }

        return Json.success();
    }
}